#pragma once
#include<iostream>
#include<queue>
#include<pthread.h>

#include"Task.hpp"
#include"Log.hpp"

static const int NUM=6;

class ThreadPool
{
private:
    int num;
    bool stop;
    std::queue<Task> task_queue;
    pthread_mutex_t lock;
    pthread_cond_t cond;
    static ThreadPool* single_instance;

    ThreadPool(int _num=NUM):num(_num),stop(false)
    {
        LOG(INFO,"create ThreadPool");
        pthread_mutex_init(&lock,nullptr);
        pthread_cond_init(&cond,nullptr);
    }
    ThreadPool(const ThreadPool&)=delete;
    ThreadPool& operator=(const ThreadPool&)=delete;
public:
    static ThreadPool* GetInstance()
    {
        static pthread_mutex_t _mutex= PTHREAD_MUTEX_INITIALIZER;
        if(single_instance==nullptr)
        {
            pthread_mutex_lock(&_mutex);
            if(single_instance==nullptr)
            {
                single_instance=new ThreadPool;
                single_instance->InitThreadPool();
            }
            pthread_mutex_unlock(&_mutex);
        }
        return single_instance;
    }
    
    bool IsStop()
    {
        return stop;
    }
    bool TaskQueueEmpty()
    {
        return task_queue.empty();
    }
    void ThreadWait()
    {
        pthread_cond_wait(&cond,&lock);
    }
    void ThreadWakeUp()
    {
        pthread_cond_signal(&cond);
    }
    void Lock()
    {
        pthread_mutex_lock(&lock);
    }
    void Unlock()
    {
        pthread_mutex_unlock(&lock);
    }

    static void*ThreadRoutine(void* args)
    {
        ThreadPool*tp=(ThreadPool*)args;
        while(true)
        {
            Task t;
            tp->Lock();
            while(tp->TaskQueueEmpty())
            {
                tp->ThreadWait();
            }
            tp->PopTask(t);
            tp->Unlock();
            t.ProcessOn();
        }
    }
    bool InitThreadPool()
    {
        for(int i=0;i<num;i++)
        {
            pthread_t tid;
            if(0!=pthread_create(&tid,nullptr,ThreadRoutine,this))
            {
                LOG(FATAL,"Create ThreadPool fail");
            }
        }
        LOG(INFO,"Create ThreadPool success");
        return true;
    }

    void PushTask(const Task&in)
    {
        Lock();
        task_queue.push(in);
        Unlock();
        ThreadWakeUp();
    }

    void PopTask(Task&out)
    {
        out=task_queue.front();
        task_queue.pop();
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&lock);
        pthread_cond_destroy(&cond);
    }
};
ThreadPool* ThreadPool::single_instance=nullptr; 